package cn.ibizlab.util.adapter.config;

import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Component
@RefreshScope
@ConfigurationProperties(prefix = "ibiz.runtime")
public class BootServiceHub {

    private BootServiceHubSetting serviceHub;
    private Map<String, BootDeploySystem> deploySystems = new LinkedHashMap<>();
    private Map<String, BootDatabaseInstance> databaseInstances = new LinkedHashMap<>();

    public void setDeploySystems(Map<String, BootDeploySystem> deploySystems) {
        if (deploySystems != null)
            deploySystems.entrySet().forEach(entry -> {
                entry.getValue().setDeploySystemId(entry.getKey());
            });
        this.deploySystems = deploySystems;
    }


    public void setDatabaseInstances(Map<String, BootDatabaseInstance> databaseInstances) {
        if (databaseInstances != null)
            databaseInstances.entrySet().forEach(entry -> {
                entry.getValue().setId(entry.getKey());
            });
        this.databaseInstances = databaseInstances;
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @RefreshScope
    public static class BootServiceHubSetting {

        @JsonProperty("deploysystems")
        @JSONField(name = "deploysystems")
        private Object deploySystems;

        @JsonProperty("tempfolder")
        @JSONField(name = "tempfolder")
        private String tempFolder;

        @JsonProperty("filefolder")
        @JSONField(name = "filefolder")
        private String fileFolder;

        @JsonProperty("systemsettings")
        @JSONField(name = "systemsettings")
        private Map systemSettings;

        public List<String> getDeploySystems() {
            List<String> deploySystemNames = null;
            if (!ObjectUtils.isEmpty(deploySystems)) {
                if (deploySystems instanceof List)
                    deploySystemNames = (List<String>) deploySystems;
                else if (deploySystems instanceof String)
                    deploySystemNames = Arrays.asList(deploySystems.toString().split(",|;"));
            }
            return deploySystemNames;
        }
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @RefreshScope
    public static class BootDatabaseInstance {

        @JsonProperty("id")
        @JSONField(name = "id")
        private String id;

        @JsonProperty("dbtype")
        @JSONField(name = "dbtype")
        private String dbType;

        @JsonProperty("username")
        @JSONField(name = "username")
        private String username;

        @JsonProperty("password")
        @JSONField(name = "password")
        private String password;

        @JsonProperty("url")
        @JSONField(name = "url")
        private String url;

    }

    public BootDeploySystem get(String systemId) {
        return getDeploySystem(systemId);
    }

    public BootDeploySystem getDeploySystem(String systemId) {
        return deploySystems.get(systemId);
    }

    public BootDatabaseInstance getDatabaseInstance(String databaseInstanceId) {
        return databaseInstances.get(databaseInstanceId);
    }


    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @RefreshScope
    public static class BootDeploySystem {
        @JsonProperty("deploysystemid")
        @JSONField(name = "deploysystemid")
        private String deploySystemId;

        @JsonProperty("runtimeclassname")
        @JSONField(name = "runtimeclassname")
        private String runtimeClassName;

        @JsonProperty("modelpath")
        @JSONField(name = "modelpath")
        private String modelPath;

        @JsonProperty("updatedbschema")
        @JSONField(name = "updatedbschema")
        private boolean updateDBSchema;

        @JsonProperty("extension")
        @JSONField(name = "extension")
        private boolean extension;

        @NestedConfigurationProperty
        private BootDeploySystemSetting settings;
    }


    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class BootDeploySystemSetting {
        @JsonProperty("sysdbscheme")
        @JSONField(name = "sysdbscheme")
        private Map<String, SysDBScheme> sysDBScheme;

        public void addSysDBScheme(String key, SysDBScheme value) {
            if (sysDBScheme == null)
                sysDBScheme = new LinkedHashMap<>();
            sysDBScheme.put(key, value);
        }


        @JsonProperty("sysbdscheme")
        @JSONField(name = "sysbdscheme")
        private Map<String, SysBDScheme> sysBDScheme;

        public void addSysBDScheme(String key, SysBDScheme value) {
            if (sysBDScheme == null)
                sysBDScheme = new LinkedHashMap<>();
            sysBDScheme.put(key, value);
        }

        @JsonProperty("subsysserviceapi")
        @JSONField(name = "subsysserviceapi")
        @NestedConfigurationProperty
        private Map<String, SubApis> subSysServiceApi;

        @JsonProperty("cloudclientutil")
        @JSONField(name = "cloudclientutil")
        @NestedConfigurationProperty
        private Map<String, SubSysServiceApi> cloudClientUtil;

        @JsonProperty("sysutil")
        @JSONField(name = "sysutil")
        @NestedConfigurationProperty
        private SysUtil sysUtil;

        public void addSysUtil(String key, Map value) {
            if (sysUtil == null)
                sysUtil = new SysUtil();
            sysUtil.put(key, value);
        }
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class SysDBScheme {

        @JsonProperty("datasource")
        @JSONField(name = "datasource")
        private String dataSource;

        @JsonProperty("dbtype")
        @JSONField(name = "dbtype")
        private String dbType;
    }

    public static class SubApis extends LinkedHashMap<String, SubApiModule> {

    }

    public static class SubApiModule extends LinkedHashMap<String, SubSysServiceApi> {

    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class SubSysServiceApi {
        @JsonProperty("serviceurl")
        @JSONField(name = "serviceurl")
        private String serviceUrl;

        @JsonProperty("globalheadermap")
        @JSONField(name = "globalheadermap")
        private Map<String, Object> globalHeaderMap;

        @JsonProperty("defaultheadermap")
        @JSONField(name = "defaultheadermap")
        private Map<String, Object> defaultHeaderMap;

        @JsonProperty("accesstokenurl")
        @JSONField(name = "accesstokenurl")
        private String accessTokenUrl;

        @JsonProperty("authmode")
        @JSONField(name = "authmode")
        private String authMode;

        @JsonProperty("clientid")
        @JSONField(name = "clientid")
        private String clientId = null;

        @JsonProperty("clientsecret")
        @JSONField(name = "clientsecret")
        private String clientSecret = null;

        @JsonProperty("tokentimeout")
        @JSONField(name = "tokentimeout")
        private Long tokenTimeout;

        @JsonProperty("defaulttokentimeout")
        @JSONField(name = "defaulttokentimeout")
        private Integer defaultTokenTimeout;
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class SysBDScheme {
        @JsonProperty("serviceurl")
        @JSONField(name = "serviceurl")
        private String serviceUrl;
    }

    public static class SysUtil extends LinkedHashMap<String, Map> {

    }


}
